/**************************************************************************************************
  Filename:       bsp_storage.c
  Revised:        $Date: 2014-12-04 10:20:18 +0800 (Fri, 04 Apr 2014) $
  Revision:       $Revision: 10001 $

  Description:    This file contains the board support package of storage data.
**************************************************************************************************/

#include "bsp_storage.h"
#include "math.h"

extern volatile uint8 __eraseFlag;
extern const uint32 dataSectorAddrs[DATA_SECTOR_COUNT];
uint32 estimatePage(uint32 addr , uint8 len);
uint32 get_next_page(uint32 addr);
void __caller(char *string,const char *caller_name);

#define caller(x) __caller(x,__func__)
void __caller(char *string,const char *caller_name)
{
	strcpy(string,caller_name);
}

uint8 UDHumiInit(UnitData *unit,uint8 *data)
{
	uint8 lenCode = getUDLenCode(getLenByTypeCode(UDTHumi));
	return UD_init(unit,UDTHumi|lenCode,data);
}
uint8 UDSlepInit(UnitData *unit,uint8 *data)
{
	uint8 lenCode = getUDLenCode(getLenByTypeCode(UDTSlep));
	return UD_init(unit,UDTSlep|lenCode,data);
}
uint8 UDRsvInit(UnitData *unit,uint8 udtype,uint8 *data)
{
	uint8 lenCode = getUDLenCode(getLenByTypeCode(udtype));
	return UD_init(unit,udtype|lenCode,data);
}
uint8 UDBattInit(UnitData *unit,uint8 *data)
{
	uint8 lenCode = getUDLenCode(getLenByTypeCode(UDTBatt));
	return UD_init(unit,UDTBatt|lenCode,data);
}
uint8 UDTimeInit(UnitData *unit,uint8 *data)
{
	uint8 lenCode = getUDLenCode(getLenByTypeCode(UDTTime));
	return UD_init(unit,UDTTime|lenCode,data);
}
// uint8 UDWarnInit(UnitData *unit,uint8 *data)
// {
// 	uint8 lenCode = getUDLenCode(getLenByTypeCode(UDTWarn));
// 	return UD_init(unit,UDTWarn|lenCode,data);
// }
// uint8 UDErroInit(UnitData *unit,uint8 *data)
// {
// 	uint8 lenCode = getUDLenCode(getLenByTypeCode(UDTErro));
// 	return UD_init(unit,UDTErro|lenCode,data);
// }
uint8 UD_init(UnitData *unit,uint8 type,uint8 *data)
{
	if (type == UDTTime)
	{
		__currentTimeUnix = osal_getClock();
		unit->meta = 0x47; // 0x40 is len 4; 0x07 is type
		unit->data[1] = (uint8)(__currentTimeUnix & 0x000000FF);
		unit->data[2] = (uint8)((uint32)((__currentTimeUnix  >> 8  ) & 0x00FF));
		unit->data[3] = (uint8)((uint32)((__currentTimeUnix  >> 16 ) & 0x00FF));
		unit->data[4] = (uint8)((uint32)((__currentTimeUnix  >> 24 ) & 0x00FF));
		return 4;
	}
	uint8 datalen = getUDLen(type);
	unit->meta = type;
	for (int8 i = datalen - 1; i >= 0; --i)
	{
		unit->data[i] = data[i];
	}
	return datalen;
}
uint8 UD_setLength(uint8 type,uint8 len)
{
	return type | getUDLenCode(len);
}
uint8 UD_setType(uint8 type,uint8 sensor)
{
	return type | sensor;
}
uint8 UD_getLength(uint8 type)
{
	return getUDLen(type) + UDHeadLen;
}
uint32 UD_write(UnitData unit,uint32 addr)
{
	uint8 datalen = getUDLen(unit.meta);
	uint32 ret = estimatePage(addr, datalen + 1);
	if ( ret != DONT_NEED_NEW_PAGE )
	{	
		addr = ret;
	}
	addr = bsp_write8b(addr,unit.meta);
	// addr = bsp_write32b(addr,unit.time);
	for (int8 i = datalen -1; i >= 0 ; --i)
	{
		addr = bsp_write8b(addr,unit.data[i]);
	}
	return addr;
}
uint32 UD_read(UnitData *unit,uint32 addr)
{
	uint8 type;
	addr = bsp_read8b(addr,&type);
	int16 left = PAGE_SIZE - 1 - addr & ADDR_INNER_MASK; // -1 means addr from zero
	if ( ( (left < 13) && (type == DUMMY_BYTE)) || left<1 )  		 //not enough for longest and type is 0xff ,then jump to next page
	{
		addr = get_next_page(addr);
		addr = bsp_read8b(addr,&type);
	}

	uint8 datalen = getUDLen(type);
	unit->meta = type;
	// addr = bsp_read32b(addr,&unit->time);
	addr = bsp_read(addr,unit->data,datalen);
	return addr;
}
uint8 UD_toString(UnitData unit,uint8 *string)
{
	string[0] = unit.meta;
	// string[1] = (uint8)(unit.time & 0x000000FF); 
	// string[2] = (uint8)((uint32)((unit.time  >> 8  ) & 0x00FF));
	// string[3] = (uint8)((uint32)((unit.time  >> 16 ) & 0x00FF));
	// string[4] = (uint8)((uint32)((unit.time  >> 24 ) & 0x00FF));

	uint8 datalen = getUDLen(unit.meta);// unitlen - UDHeadLen;
	for (int8 i = datalen - 1; i >=0 ; --i)
	{	//5 + (datalen -1 -i)                   //MSB is the biggest idx
		string[0 + datalen - i] = unit.data[i];	
	}
	return datalen;
}
uint8 getUDLen(uint8 type)
{
	switch(type & 0xC0 )
	{
		case UDLen2:
			return 2;
		case UDLen4:
			return 4;
		case UDLen6:
			return 6;
		case UDLen8:
			return 8;
		default:
			break;
	}
	return 2;
}
uint8 getLenByTypeCode(uint8 type)
{
	switch(type)
	{
		case UDTHumi:
		case UDTTemp:
			return 4;
		case UDTSlep:
			return 6;
		case UDTGyro:
			return 6;
		case UDTRsv2:
		case UDTRsv3:
		case UDTBatt:
		case UDTTime:
			return 4;
		default:
			return 2;
	}
}
uint8 getUDLenCode(uint8 len)
{
	switch(len)
	{
		case 2:
			return UDLen2;
		case 4:
			return UDLen4;
		case 6:
			return UDLen6;
		case 8:
			return UDLen8;
		default:
			break;
	}
	return UDLen2;
}
/*********************
 * 
 * MSB save unit32 data
 * @params: addr first 
 * @return: next addr
 *
*********************/
uint32 bsp_write32b(uint32 addr,uint32 data)
{
	uint8 buffer[4];//(uint8)((uint32)((unit.time  >> 24 ) & 0x00FF));
	buffer[3] = (uint8)((uint32)((data >> 24) & 0x00FF));
	buffer[2] = (uint8)((uint32)((data >> 16) & 0x00FF));
	buffer[1] = (uint8)((uint32)((data >> 8) & 0x00FF));
	buffer[0] = (uint8)(data & 0x00FF);
	// uint32 ret = estimatePage(addr,4);
	// if ( ret != DONT_NEED_NEW_PAGE )
	// {	
	// 	unit32 newaddr = getNextPage(addr);
	// 	DBWrite(newaddr,buffer,4);
	// 	return newaddr + 4;
	// }
	DBWrite(addr,buffer,4);
	return addr + 4;
}
uint32 bsp_write32bERASE(uint32 addr,uint32 data)
{
	uint8 buffer[4];//(uint8)((uint32)((unit.time  >> 24 ) & 0x00FF));
	buffer[3] = (uint8)((uint32)((data >> 24) & 0x00FF));
	buffer[2] = (uint8)((uint32)((data >> 16) & 0x00FF));
	buffer[1] = (uint8)((uint32)((data >> 8) & 0x00FF));
	buffer[0] = (uint8)(data & 0x00FF);
	DBWritePageThroughBuffer1(addr,buffer,4);
	return addr + 4;
}


uint32 bsp_write8b(uint32 addr, uint8 data)
{
	DBWrite(addr,&data,1);
	return addr + 1;
}
uint32 bsp_write(uint32 addr,uint8 volatile *buffer,uint8 len)
{
	DBWrite(addr,(uint8 *)buffer,len);
	return addr + len;
}
uint32 bsp_read32b(uint32 addr,uint32 volatile *data)
{
	uint8 buffer[4];
	DBRead(addr,buffer,4);
	*data = BUILD_UINT32(buffer[0],buffer[1],buffer[2],buffer[3]);
	return addr + 4;
}
uint32 bsp_read8b(uint32 addr,uint8 volatile *data)
{
    uint8 tmpdata;
    DBRead(addr,&tmpdata,1);
    *data = tmpdata;
    return addr + 1;
}
uint32 bsp_read(uint32 addr,uint8 volatile *buffer,uint8 len)
{
	DBRead(addr,(uint8 *)buffer,len);
	return addr + len;
}


uint32 estimatePage(uint32 addr , uint8 len)
{
        int16 left = PAGE_SIZE - 1 - addr & ADDR_INNER_MASK; // -1 means addr from zero
        if (left > len)
        {
                return DONT_NEED_NEW_PAGE;
        }
        else
        {
        	char caller_name[10];
        	caller(caller_name);
        	if (strstr(caller_name,"write") != NULL)
        	{
	        	if (left >= 1)
	        	{
	        		bsp_write8b(addr,DUMMY_BYTE);
	        	}
	            if(ADDR_LAST_PAGE == addr & ~ADDR_INNER_MASK)
	            {
	              __eraseFlag = 0;
	              DBSectorErase(dataSectorAddrs[__eraseFlag],BLOCK);
	            }
	            else
	            {
	              __eraseFlag++;
	              DBSectorErase(dataSectorAddrs[__eraseFlag],BLOCK);
	            }
        	}
           	return get_next_page(addr);
        }
}

uint32 get_next_page(uint32 addr)
{
    addr =  addr & ~ADDR_INNER_MASK;
    if(addr == ADDR_LAST_PAGE)
    {
         return DATA_START;
    }
    return addr  + ADDR_ONE_PAGE;
}


/****************
*
*	Data Page Init and Operation
* 
****************/
	// uint32 datasize;
	// uint8 status;
	// uint32 iterAddr;
	// uint32 startAddr;
	// uint32 endAddr;
	// uint32 newAddr;
	// uint32 lastUpdateTime;
	// uint32 lastSyncTime;
void bsp_dataPgInit(void)
{
	_dataPg.datasize = 0;
	_dataPg.status = META_DATA_NORMAL;
	_dataPg.iterAddr = DATA_START;
	_dataPg.startAddr = DATA_START;
	_dataPg.endAddr = DATA_START;
	_dataPg.newAddr  = DATA_START;
	_dataPg.lastUpdateTime = 0;
	_dataPg.lastSyncTime = 0;
	bsp_dataPg2Mem();
}
void bsp_mem2dataPg(void)
{
	uint32 addr = DATA_INFO;
	addr = bsp_read32b(addr, &(_dataPg.datasize));
	addr = bsp_read8b(addr,&(_dataPg.status));
	addr = bsp_read32b(addr,&(_dataPg.iterAddr));
	addr = bsp_read32b(addr,&(_dataPg.startAddr));
	addr = bsp_read32b(addr,&(_dataPg.endAddr));
	addr = bsp_read32b(addr,&(_dataPg.newAddr));
	addr = bsp_read32b(addr,&(_dataPg.lastUpdateTime));
	addr = bsp_read32b(addr,&(_dataPg.lastSyncTime));
	__currentAddr = _dataPg.newAddr;
	__iterAddr    = _dataPg.iterAddr;
}
void bsp_updateAddr(void)
{
	uint32 addr = DATA_INFO;
	addr = bsp_read32b(addr, &(_dataPg.datasize));
	addr = bsp_read8b(addr,&(_dataPg.status));
	addr = bsp_read32b(addr,&(_dataPg.iterAddr));
	addr = bsp_read32b(addr,&(_dataPg.startAddr));
	addr = bsp_read32b(addr,&(_dataPg.endAddr));
	addr = bsp_read32b(addr,&(_dataPg.newAddr));
	__currentAddr = _dataPg.newAddr;
	__iterAddr	 = _dataPg.iterAddr;
}
void bsp_dataPg2Mem(void)
{
	uint32 addr = DATA_INFO;
	_dataPg.iterAddr = __iterAddr;
	addr = bsp_write32b(addr,_dataPg.datasize);
	addr = bsp_write8b(addr,_dataPg.status);
	addr = bsp_write32b(addr,_dataPg.iterAddr);
	addr = bsp_write32b(addr,_dataPg.startAddr);
	addr = bsp_write32b(addr,_dataPg.endAddr);
	addr = bsp_write32b(addr,_dataPg.newAddr);
	addr = bsp_write32b(addr,_dataPg.lastUpdateTime);
	addr = bsp_write32b(addr,_dataPg.lastSyncTime);
}
/****************
*
*	User Page Init and Operation
* 
****************/
// uint8 name[24];
// uint32 age;
// uint8 toy[84];
// uint8 food[84];
// uint8 allergy[60];	
void bsp_userPgInit(void)
{
	VOID osal_memset((uint8 *)_userPg.name,0,24);
	_userPg.age = 0;
	VOID osal_memset((uint8 *)_userPg.toy,0,84);
	VOID osal_memset((uint8 *)_userPg.food,0,84);
	VOID osal_memset((uint8 *)_userPg.allergy,0,60);
	bsp_userPg2Mem();
        WAIT_MS(100);
}
void bsp_mem2userPg(void)
{
	uint32 addr = USER_INFO;
	addr = bsp_read(addr,_userPg.name,24);
	addr = bsp_read32b(addr,&_userPg.age);
	addr = bsp_read(addr,_userPg.allergy,84);
	addr = bsp_read(addr,_userPg.toy,84);
	addr = bsp_read(addr,_userPg.food,60);

}
void bsp_userPg2Mem(void)
{
	uint32 addr = USER_INFO;
	addr = bsp_write(addr,_userPg.name,24);
	addr = bsp_write32b(addr,_userPg.age);
	addr = bsp_write(addr,_userPg.allergy,84);
	addr = bsp_write(addr,_userPg.toy,84);
	addr = bsp_write(addr,_userPg.food,60);
}
/****************
*
*	Security Page Init and Operation
* 
****************/
/*
uint8 username[12];		//use phone
uint8 password[36];
uint8 fatherName[24];
uint8 motherName[24];
uint8 fatherPhone[12];
uint8 motherPhone[12];
uint8 address[96];
*/
void bsp_secuInit(void)
{
	VOID osal_memset((uint8 *)_secuPg.username,0,12);
	VOID osal_memset((uint8 *)_secuPg.password,0,36);
	VOID osal_memset((uint8 *)_secuPg.fatherName,0,24);
	VOID osal_memset((uint8 *)_secuPg.motherName,0,24);
	VOID osal_memset((uint8 *)_secuPg.fatherPhone,0,12);
	VOID osal_memset((uint8 *)_secuPg.motherPhone,0,12);
	VOID osal_memset((uint8 *)_secuPg.address,0,96);
	bsp_secuPg2Mem();WAIT_MS(100);
}
void bsp_mem2secuPg(void)
{
	uint32 addr = SECU_DATA;
	addr = bsp_read(addr,_secuPg.username,12);
	addr = bsp_read(addr,_secuPg.password,36);
	addr = bsp_read(addr,_secuPg.fatherName,24);
	addr = bsp_read(addr,_secuPg.motherName,24);
	addr = bsp_read(addr,_secuPg.fatherPhone,12);
	addr = bsp_read(addr,_secuPg.motherPhone,12);
	addr = bsp_read(addr,_secuPg.address,96);
}
void bsp_secuPg2Mem(void)
{
	uint32 addr = SECU_DATA;
	addr = bsp_write(addr,_secuPg.username,12);
	addr = bsp_write(addr,_secuPg.password,36);
	addr = bsp_write(addr,_secuPg.fatherName,24);
	addr = bsp_write(addr,_secuPg.motherName,24);
	addr = bsp_write(addr,_secuPg.fatherPhone,12);
	addr = bsp_write(addr,_secuPg.motherPhone,12);
	addr = bsp_write(addr,_secuPg.address,96);
}
/****************
*
*	Time Page Init and Operation
* 
****************/
void bsp_timeSave(void)
{
	_timePg.time = __currentTimeUnix;
 	bsp_timePg2Mem();WAIT_MS(100);
}
void bsp_updateTime(void)
{
	bsp_read32b(TIME_DATA,&(_timePg.time));
    osal_setClock(_timePg.time);
}
void bsp_timePg2Mem(void)
{
	bsp_write32b(TIME_DATA,_timePg.time);
}
/****************
*
*	Setting Page Init and Operation
* 
****************/
	// uint32 intervalTime;
	// uint32 diaper_interval;
	// uint32 diaper_number;
	// uint32 diaper_factor;
	// uint32 sleep_interval;
	// uint32 sleep_factor;
	// uint32 motion_interval;
	// uint32 motion_fator;
	// uint32 batt_interval;
	// uint32 batt_factor;
	// uint8 type[8];
	// uint8 position[8];
void bsp_settingsInit(void)
{
	// VOID osal_memset((uint8 *)_settingsPg.setting,0,32);
	_settingsPg.update_flag = 0 ;
	_settingsPg.intervalTime = 0;
	_settingsPg.diaper_interval= 0;
	_settingsPg.diaper_number= 0;
	_settingsPg.diaper_factor= 0;
	_settingsPg.sleep_interval= 0;
	_settingsPg.sleep_factor= 0;
	_settingsPg.motion_interval= 0;
	_settingsPg.motion_factor= 0;
	_settingsPg.batt_interval= 0;
	_settingsPg.batt_factor= 0;
	_settingsPg.update_interval = 0;
	VOID osal_memset((uint8 *)_settingsPg.type,0,8);
	VOID osal_memset((uint8 *)_settingsPg.position,0,8);
	bsp_setPg2Mem();
	WAIT_MS(100);
}
void bsp_mem2setPg(void)
{
	uint32 addr = SETTINGS;
	addr = bsp_read8b(addr,&_settingsPg.update_flag);
	addr = bsp_read32b(addr,&_settingsPg.intervalTime);
	addr = bsp_read32b(addr,&_settingsPg.diaper_interval);
	addr = bsp_read32b(addr,&_settingsPg.diaper_number);
	addr = bsp_read32b(addr,&_settingsPg.diaper_factor);
	addr = bsp_read32b(addr,&_settingsPg.sleep_interval);
	addr = bsp_read32b(addr,&_settingsPg.sleep_factor);
	addr = bsp_read32b(addr,&_settingsPg.motion_interval);
	addr = bsp_read32b(addr,&_settingsPg.motion_factor);
	addr = bsp_read32b(addr,&_settingsPg.batt_interval);
	addr = bsp_read32b(addr,&_settingsPg.batt_factor);
	addr = bsp_read32b(addr,&_settingsPg.update_interval);
	addr = bsp_read(addr,_settingsPg.type,8);
	addr = bsp_read(addr,_settingsPg.position,8);	
}
void bsp_setPg2Mem(void)
{
	uint32 addr = SETTINGS;
	addr = bsp_write8b(addr,_settingsPg.update_flag);
	addr = bsp_write32b(addr,_settingsPg.intervalTime);
	addr = bsp_write32b(addr,_settingsPg.diaper_interval);
	addr = bsp_write32b(addr,_settingsPg.diaper_number);
	addr = bsp_write32b(addr,_settingsPg.diaper_factor);
	addr = bsp_write32b(addr,_settingsPg.sleep_interval);
	addr = bsp_write32b(addr,_settingsPg.sleep_factor);
	addr = bsp_write32b(addr,_settingsPg.motion_interval);
	addr = bsp_write32b(addr,_settingsPg.motion_factor);
	addr = bsp_write32b(addr,_settingsPg.batt_interval);
	addr = bsp_write32b(addr,_settingsPg.batt_factor);
	addr = bsp_write32b(addr,_settingsPg.update_interval);
	addr = bsp_write(addr,_settingsPg.type,8);
	addr = bsp_write(addr,_settingsPg.position,8);
}
/****************
*
*	Hardware Page Init and Operation
* 
****************/
	// uint32 manufacture;
	// uint32 version;
	// uint32 firmversion;
	// uint32 firstOn;
	// uint32 firstSync;
	// uint32 lastUpdate;
void bsp_flashInitFlag(void)
{
	uint32 addr = HW_INFO;
	addr = bsp_read8b(addr,&(_hardPg.flag));
}

void bsp_updateHardware(void)
{
	uint32 addr = HW_INFO;
	addr = bsp_read8b(addr,&_hardPg.flag);
	addr = bsp_read32b(addr,&_hardPg.manufacture);
	addr = bsp_read32b(addr,&_hardPg.version);
	addr = bsp_read32b(addr,&_hardPg.firmversion);
	addr = bsp_read32b(addr,&_hardPg.firstOn);
	addr = bsp_read32b(addr,&_hardPg.firstSync);
	addr = bsp_read32b(addr,&_hardPg.lastUpdate);
	addr = bsp_read32b(addr,&_hardPg.deviceID);
}
void bsp_hardwareInit(void)
{
	_hardPg.flag = HARDWARE_INITIALIZED;
	_hardPg.manufacture = 0x4d54544b;               //MTTK
	_hardPg.version = 0x00000101;		//00.01.01
	_hardPg.firmversion = 0x00000001; 	//00.00.01
	_hardPg.firstOn = __currentTimeUnix;
	_hardPg.firstSync = __currentTimeUnix;
	_hardPg.lastUpdate = __currentTimeUnix;
	_hardPg.deviceID = 0xDFECDEDA;
	bsp_hwPg2Mem();WAIT_MS(100);
}
void bsp_hwPg2Mem(void)
{
	uint32 addr = HW_INFO;
	addr = bsp_write8b(addr,_hardPg.flag);
	addr = bsp_write32b(addr,_hardPg.manufacture);
	addr = bsp_write32b(addr,_hardPg.version);
	addr = bsp_write32b(addr,_hardPg.firmversion);
	addr = bsp_write32b(addr,_hardPg.firstOn);
	addr = bsp_write32b(addr,_hardPg.firstSync);
	addr = bsp_write32b(addr,_hardPg.lastUpdate);
	addr = bsp_write32b(addr,_hardPg.deviceID);
}





